/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Simulator;


/**
 *The Moper class is responsible for computing all MOPER operations.
 * @author khhill
 */
public class Moper {

    
    /**
* The Add function will be called when the function bits are 000.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, adds the operand, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Value at memory is not defined. <br>
     * 170 - Operation exceeded bounds of memory.  Original stack replaced.<br>
* <p>
* <b>Date of module being installed:</b> 5/19/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation.3000 is returned if an invalid memory reference was found.
*/
    private static int Add(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        if(lit_flag.equals("0")){
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }
        }
        
        int top_of_stack = Stack.PopData();
        top_of_stack = top_of_stack + operand;
        if(top_of_stack > 65535 || top_of_stack < -65536){
            System.out.println("Error 170:  Operation exceeded bounds of memory.  Original top of stack replaced.");
            top_of_stack = top_of_stack - operand;
            return_value = 1000;
        }
        
        
        Stack.PushData(top_of_stack);
        return return_value;
    }

        /**
* The Sub function will be called when the function bits are 001.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, subtracts the operand, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Value at memory is not defined. <br>
     * 170 - Operation exceeded bounds of memory.  Original stack replaced.<br>
* <p>
* <b>Date of module being installed:</b> 5/19/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation.3000 is returned if an invalid memory reference was found.
*/
    private static int Sub(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        if(lit_flag.equals("0")){
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                return_value = 3000;
                operand = 0;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }
        }
        
        int top_of_stack = Stack.PopData();
        top_of_stack = top_of_stack - operand;
        if(top_of_stack > 65535 || top_of_stack < -65536){
            System.out.println("Error 170:  Operation exceeded bounds of memory.  Original top of stack replaced.");
            top_of_stack = top_of_stack + operand;
            return_value = 1000;
        }
        
        
        Stack.PushData(top_of_stack);
        return return_value;
    }
        /**
* The Mut function will be called when the function bits are 010.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, multiplies the operand, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Value at memory is not defined. <br>
     * 170 - Operation exceeded bounds of memory.  Original stack replaced.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/85
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation.3000 is returned if an invalid memory reference was found.
*/    
    
    private static int Mut(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        if(lit_flag.equals("0")){
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }
        }
        
        int top_of_stack = Stack.PopData();
        top_of_stack = top_of_stack * operand;
        if(top_of_stack > 65535 || top_of_stack < -65536){
            System.out.println("Error 170:  Operation exceeded bounds of memory.  Original top of stack replaced.");
            top_of_stack = top_of_stack / operand;
            return_value = 1000;
        }
        
        
        Stack.PushData(top_of_stack);
        return return_value;
    }
    
            /**
* The Div function will be called when the function bits are 011.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, divides the operand, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Value at memory is not defined. <br>
     * 170 - Operation exceeded bounds of memory.  Original stack replaced.<br>
     * 171 - Divide by 0.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/85
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation.  4000 is returned if a divide by 0 is encountered. 3000 is returned if an invalid memory reference was found.
*/
    private static int Div(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        if(lit_flag.equals("0")){
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }
        }
        
        int top_of_stack = Stack.PopData();
        if(operand == 0){
            System.out.println("Error 171: Divide by 0.  Operation not completed");
            Stack.PushData(top_of_stack);
            return_value = 4000;
            return return_value;
        }
        top_of_stack = top_of_stack / operand;
        if(top_of_stack > 65535 || top_of_stack < -65536){
            System.out.println("Error 170:  Operation exceeded bounds of memory.  Original top of stack replaced.");
            top_of_stack = top_of_stack * operand;
            return_value = 1000;
        }
        
        
        Stack.PushData(top_of_stack);
        return return_value;
        
    }
    
        /**
* The Or function will be called when the function bits are 100.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, or's the operand, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Value at memory is not defined. <br>
     * 170 - Operation exceeded bounds of memory.  Original stack replaced.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/85
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation.
*/       
    private static int Or(String bit_code,String lit_flag){
        IceAssembly.Convert convert_instance = new IceAssembly.Convert();
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        if(lit_flag.equals("0")){
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }
        }
        String soperand = String.valueOf(operand);
        soperand = convert_instance.getBitCode(soperand, 16);
        int top_of_stack = Stack.PopData();
        int temp = top_of_stack; // in case we need to revert
        String stop_of_stack = String.valueOf(top_of_stack);
        stop_of_stack = convert_instance.getBitCode(stop_of_stack, 16);
        
        int counter = 0;
        String result = "";
        while(counter <16){
            if(stop_of_stack.charAt(counter) == '1' || soperand.charAt(counter)=='1'){
                result = result + "1";
            }
            else{
                result = result + "0";
            }
            counter ++;
        }
        top_of_stack = Integer.parseInt(result, 2);
        if(top_of_stack > 65535 || top_of_stack < -65536){
            System.out.println("Error 170:  Operation exceeded bounds of memory.  Original top of stack replaced.");
            top_of_stack = temp;
            return_value = 1000;
        }
        Stack.PushData(top_of_stack);
        
        return return_value;
    }

            /**
* The And function will be called when the function bits are 101.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value in the data stack, and's the operand, and pushes the new value.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Value at memory is not defined. <br>
     * 170 - Operation exceeded bounds of memory.  Original stack replaced.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/85
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  1000 is returned if there was an overflow on computation.
*/ 
    private static int And(String bit_code,String lit_flag){
        IceAssembly.Convert convert_instance = new IceAssembly.Convert();
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        if(lit_flag.equals("0")){
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }
        }
        String soperand = String.valueOf(operand);
        soperand = convert_instance.getBitCode(soperand, 16);
        int top_of_stack = Stack.PopData();
        int temp = top_of_stack; // in case we need to revert
        String stop_of_stack = String.valueOf(top_of_stack);
        stop_of_stack = convert_instance.getBitCode(stop_of_stack, 16);
        
        int counter = 0;
        String result = "";
        while(counter <16){
            if(stop_of_stack.charAt(counter) == '1' && soperand.charAt(counter)=='1'){
                result = result + "1";
            }
            else{
                result = result + "0";
            }
            counter ++;
        }
        top_of_stack = Integer.parseInt(result, 2);
        if(top_of_stack > 65535 || top_of_stack < -65536){
            System.out.println("Error 170:  Operation exceeded bounds of memory.  Original top of stack replaced.");
            top_of_stack = temp;
            return_value = 1000;
        }
        Stack.PushData(top_of_stack);
        
        return return_value;
        
    }
    
               /**
* The Read function will be called when the function bits are 111.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then reads from the read file and stores it from memory.<p>
* <p>
* <b>Change Log:</b><br>
* Removed ability to allow literals - Keith - 5/28/08<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 176 - Attempting to write to a location in memory outside of the scope of this program.  Line ignored.<br>
* 177 - Failed to read from the read file.  Read count max reached.  Line ignored<br>
* <p>
* <b>Date of module being installed:</b> 5/24/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
* @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the memory location is not defined. 5000 is returned if the destination memory is out of range
*/    
    private static int Read(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
            if(operand < Control.starting_location || operand > Control.max_location){
                System.out.println("Error 176: Attempting to write to a location in memory outside of the scope of this program.  Line ignored.");               
                return_value = 5000;
                return return_value;
            }
        
        if(Control.read_counter >= Control.read_size){
            System.out.println("Error 177: Failed to read from the read file.  Read count max reached.  Line ignored");
            return_value = 2000;
        }
        else{
            Control.memory[operand] = Control.read_string[Control.read_counter];
            Control.read_counter++;
        }
        
        return return_value;
    }
    
            /**
* The Write function will be called when the function bits are 111.  The function will first get an interger value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then writes the appropriate value.<p>
* <p>
* <b>Change Log:</b><br>
* Removed ability to allow literals - Keith - 5/28/08<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Value at memory is not defined. <br>
* <p>
* <b>Date of module being installed:</b> 5/21/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
* @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the memory location is not defined.
*/    
    private static int Write(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);      
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.");
                operand = 0;
                return_value = 2000;
            }
        
        if(return_value != 2000){
            System.out.println(operand);
        }
        
        return return_value;
    }
    
        /**
    * The Control function will recive the call from the Simulator's Control class.  It will receive the bit 
         * information.  It will start by throwing away the first two bits since they are no longer needed.  It will then 
         * check the next three bits and call the appropriate function class with the literal flag and the operand bits as 
         * parameters.
    * <p>
    * <b>Change Log:</b><br>
    * None<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * None <br>
    * <p>
    * <b>Date of module being installed:</b> 5/19/08
    * <p><b>Original Author:</b>  Keith Hill
    * @param bit_code This is the incomming bit code that will be processed.
    */
    public static void Control(String bit_code){
        bit_code = bit_code.replaceFirst("11", "");
        String function = bit_code.substring(0, 3);
        bit_code = bit_code.replaceFirst(function, "");
        String lit_flag = bit_code.substring(0,1);
        bit_code = bit_code.replaceFirst(lit_flag, "");
        
        int result = 0;
        if(function.equals("000")){
            result = Add(bit_code,lit_flag);
        }
        else if(function.equals("001")){
            result = Sub(bit_code,lit_flag);
        }
        else if(function.equals("010")){
            result = Mut(bit_code,lit_flag);
        }
        else if(function.equals("011")){
            result = Div(bit_code,lit_flag);
        }
        else if(function.equals("100")){
            result = Or(bit_code,lit_flag);
        }
        else if(function.equals("101")){
            result = And(bit_code,lit_flag);
        }
        else if(function.equals("110")){
            result = Read(bit_code,lit_flag);
        }
        else if(function.equals("111")){
            result = Write(bit_code,lit_flag);
        }
        else{
            System.out.println("How the fuck did that happen?");
        }
        
        IceAssembly.Convert convert_instance = new IceAssembly.Convert();
        String status_result=convert_instance.getBitCode(String.valueOf(Control.location_counter), 10);
        if(result == 1){
            status_result =  "000000"+status_result;
        }
        else if(result == 1000){
            status_result = "110000"+status_result;
        }
        else if(result == 2000){
            status_result = "100000"+status_result;
        }
        else if(result ==3000){
            status_result = "000001"+status_result;
        }
        else if(result == 4000){
            status_result = "100100"+status_result;
        }
        else if(result == 5000){
            status_result = "100001"+status_result;
        }
        status_result = convert_instance.binaryToHex(status_result);
        while(status_result.length()<4){
            status_result = "0" + status_result;
        }
        Stack.PushStatus(status_result);
        Control.location_counter++;
    }

}
